﻿package  {
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.display.InterpolationMethod;
	import flash.display.Shape;
	import flash.display.SpreadMethod;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.BevelFilter;
	import flash.filters.BitmapFilterType;
	import flash.filters.BlurFilter;
	import flash.filters.GlowFilter;
	import flash.filters.GradientGlowFilter;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	public class Squid extends Sprite {
		private static const TENTACLES:Number = 8;
		//private static const TENTACLES:Number = 2;
		//private static const BURST_FRAMES:Number = 60;
		//private static const BURST_RANDOM:Number = 40;
		//private static const BURST_FRAMES:Number = 300;
		private static const BURST_FRAMES:Number = 500;
		private static const BURST_RANDOM:Number = 40;
		
		private var p:Point = new Point();
		private var v:Point = new Point();
		private var ang:Number = 0;
		
		private var container:Rectangle;
		
		public var originalTarget:Point = new Point();
		/** Dynamically modified target based on the originalTarget and velocity */
		private var target:Point = new Point();
		public var nextTarget:Boolean = true;
		public var targetTimeout:int = -1;
		
		private var burstFrames:Number = BURST_FRAMES;
		
		private var burst:Boolean = false;
		
		private var inc:Number;
		private var burstInc:Number;
		
		//private var burstMode:Boolean = Boolean(Math.random() < 0.5);
		private var burstMode:Boolean = false;
		
		private var removal:Boolean = false;
		
		private var tentacles:Vector.<Tentacle> = new Vector.<Tentacle>();
		private var tentacleDisplay:Sprite;
		private var overlay:Shape;
		private var headAngle:Number = 0;
		
		private var color:uint;
		
		public function Squid(x:Number, y:Number, container:Rectangle) {
			this.x = x;
			this.y = y;
			this.container = container;
			
			//v.x = 10;
			
			addChild(tentacleDisplay = new Sprite());
			for (var i:int = 0; i < TENTACLES; i++) {
				var t:Tentacle = new Tentacle(x, y);
				//t.filters = [new GlowFilter(0x000000, 1, 2, 2, 1, 3, true)];
				tentacleDisplay.addChild(t);
				//addChild(t);
				tentacles.push(t);
			}
			
			
			addChild(overlay = new Shape());
			
			var g:Graphics = overlay.graphics;
			g.clear();
			//g.beginFill(0xFFFFFF, 1);
			
			
			var headSize:Number = 15;
			var m:Matrix = new Matrix();
			
			
			m.createGradientBox(headSize, headSize, 0, -headSize/2, -headSize/2);
			g.beginGradientFill(GradientType.RADIAL, [0xFFFF90, 0x000000], [0.9, 0], [50, 255], m, SpreadMethod.PAD, InterpolationMethod.RGB, 0.5);
			//g.drawCircle(0, 0, headSize);
			
			
			/*
			m.createGradientBox(headSize, headSize, 0, -headSize/2, -2-headSize/2);
			g.beginGradientFill(GradientType.RADIAL, [0xFFFFFF, 0x000000], [1, 0], [50, 255], m, SpreadMethod.PAD, InterpolationMethod.RGB, 0.8);
			g.drawCircle(0, -2, headSize);
			
			m.createGradientBox(headSize, headSize, 0, -headSize/2, 2-headSize/2);
			g.beginGradientFill(GradientType.RADIAL, [0xFFFFFF, 0x000000], [1, 0], [50, 255], m, SpreadMethod.PAD, InterpolationMethod.RGB, 0.8);
			g.drawCircle(0, 2, headSize);
			*/
			
			//g.beginFill(0x00FF00, 0.5);
			
			
			//tentacleDisplay.alpha = 0.1;
			//tentacleDisplay.alpha = 0.5;
			//filters = [new GlowFilter(0x3D4AF8, 0.5, 8, 8, 2, 3)];
			//filters = [new GlowFilter(0x2C31F3, 1, 1, 1, 3, 1, false, true)];
			//filters = [new GlowFilter(0xFFFFFF, 0.5, 2, 2, 3, 1, false, true)];
			//filters = [new GlowFilter(0x0000FF, 1, 2, 2, 3, 1, true, false)];
			//filters = [new BlurFilter(4, 4, 1)];
			//filters = [new GlowFilter(0xCCCFFD, 0.5, 8, 8, 1, 3, true)];
			//filters = [new BevelFilter(4, 45, 0x4F5BF9, 0.25, 0x0615C8, 0.25, 8, 8)];
			//filters = [new GlowFilter(0xF9D60F, 1, 16, 16, 2, 1, true)];
			//filters = [new GlowFilter(0x000000, 1, 8, 8, 2, 1, true)];
			//filters = [new GlowFilter(0xFFFFFF, 0.75, 8, 8, 0.7, 2, true)];
			//filters = [new GradientGlowFilter(8, 45, [0xFFFF00, 0xFFFFFF], [1, 1], [0, 255], 4, 4, 1, 1, BitmapFilterType.INNER)];
			
			inc = Math.random()*100;
			burstInc = Math.random()*burstFrames;
			
			//alpha = 0.1;
			
			//randomizeTarget();
		}
		override public function get x():Number {
			return p.x;
		}
		override public function get y():Number {
			return p.y;
		}
		override public function set x(value:Number):void {
			p.x = value;
		}
		override public function set y(value:Number):void {
			p.y = value;
		}
		public function get position():Point {
			return p;
		}
		
		public function setColor(c:uint):void {
			color = c;
		}
		
		public function remove():void {
			removal = true;
		}
		
		
		
		public function setTarget(x:Number, y:Number):void {
			originalTarget.x = x;
			originalTarget.y = y;
		}
		
		public function randomizeTarget():void {
			//target = new Point();
			//target.x = container.x+container.width*Math.random();
			//target.y = container.y+container.height*Math.random();
			originalTarget = new Point(container.x+container.width*Math.random(), container.y+container.height*Math.random());
		}
		public function update():void {
			/*a.x /= 1.5;
			a.y /= 1.5;
			
			v.x += a.x;
			v.y += a.y;
			*/
		
			//g.drawCircle(x, y, headSize);
			
			//g.clear();
			//g.beginFill(0x00FF00, 1);
			//g.drawCircle(target.x, target.y, 10);
			//g.drawCircle(x, y, 25);
			
			overlay.x = x;
			overlay.y = y;
			headAngle += angleDifference(ang, headAngle)*0.5;
			overlay.rotation = headAngle/Math.PI*180;
			
			target.x = originalTarget.x-v.x*70;
			target.y = originalTarget.y-v.y*70;
			
			//g.drawCircle(target.x, target.y, 5);
			
			if (Point.distance(p, target) < 100 && targetTimeout == -1) {
			//if (targetTimeout == -1) {
				targetTimeout = Math.random()*400;
				//targetTimeout = Math.random()*600;
				//targetTimeout = Math.random()*100;
				//targetTimeout = 0;
			}
			if (targetTimeout > -1) {
				targetTimeout--;
				if (targetTimeout == -1) {
					//randomizeTarget();
					nextTarget = true;
				}
			}
				
			/*
			if (removal) {
				removeSpread();
			}
			*/
			
			var a:Point = new Point();
			
			//burstMode = Point.distance(p, target) > 300;
			//burstMode = Point.distance(p, target) > 200;
			//burstMode = Point.distance(p, target) > 120;
			//burstMode = true;
			
			if (burstMode) {
				moveBursts(a);
				if (burstInc == 0 && Point.distance(p, target) < 200) burstMode = false;
			} else {
				//burstInc = burstFrames/2;
				moveLinear(a);
				if (Point.distance(p, target) > 200) burstMode = true;
			}
			
			//burstMode = burstInc < 10 && Point.distance(p, target) > 100;
			
			for (var i:int = 0; i < TENTACLES; i++) {
				var t:Tentacle = tentacles[i];
				//t.color = color;
				t.hue = getHue(color);
				t.speed = v.length;
				//ConsoleUtil.print(color);
				t.update();
			}
			
			v.x += a.x;
			v.y += a.y;
			
			//v.x /= 1.05; v.y /= 1.05;
			v.x /= 1.01; v.y /= 1.01;
			//v.x /= 1.005; v.y /= 1.005;
			
			p.x += v.x;
			p.y += v.y;
		}
		private function moveBursts(a:Point):void {
			/*
			if (food) {
				var target:Point = getTarget(food);
				var angle:Number = Math.atan2(target.y-p.y, target.x-p.x);
				
				ang += angleDifference(angle, ang)/20;
				ang %= Math.PI*2;
			}
			*/
			if (target) {
				var angle:Number = Math.atan2(target.y-p.y, target.x-p.x);
				
				ang += angleDifference(angle, ang)/20;
				ang %= Math.PI*2;
			}
			if (burst) {
				//ang = angle;
				a.x = Math.cos(ang)*0.05;
				a.y = Math.sin(ang)*0.05;
				//a.x = Math.cos(ang)*0.02;
				//a.y = Math.sin(ang)*0.02;
			}
			for (var i:int = 0; i < TENTACLES; i++) {
				var t:Tentacle = tentacles[i];
				t.burst = burst;
				//t.update(p, inc, Math.PI*i%2-inc/100+Math.PI/2);
				//t.update(p, inc, -(i%2*2-1)*((inc+i/TENTACLES/2*10)%BURST_FRAMES/BURST_FRAMES+(Math.random()-0.5)/20)*Math.PI/1.4);
				//t.update(p, inc, -(i%2*2-1)*(inc/BURST_FRAMES+i/TENTACLES/2/10)*Math.PI/1.4);
				
				var ta:Number = (inc+i/TENTACLES)*Math.PI*2;
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)*Math.sin(burstInc/100)*Math.PI/2, (Math.sin(ta+Math.PI/2)+1)/2);
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)*Math.sin(burstInc/100)*Math.PI/2);
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)*Math.sin(burstInc/130)*Math.PI/2);
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)*Math.sin(burstInc/burstFrames*Math.PI*0.5)*Math.PI/2);
				t.pos.x = p.x;
				t.pos.y = p.y;
				//t.angle = Math.PI+ang+Math.sin(ta)*Math.sin(burstInc/burstFrames*Math.PI*0.5)*Math.PI/2;
				t.angle = Math.PI+ang+Math.sin(ta)*Math.sin(burstInc/burstFrames*Math.PI*0.5)*Math.PI*0.7;
			}
			
			//burstInc += burst ? -5 : 4;
			burstInc += burst ? -13 : 5;
			if (burstInc > burstFrames) {
				burstInc = burstFrames;
				burst = true;
			} else if (burstInc < 0) {
				burstInc = 0;
				burst = false;
				burstFrames = BURST_FRAMES+Math.random()*BURST_RANDOM;
			}
			
			//inc += a.length/50;
			//inc += burst ? 0.02 : 0.01;
			//inc += a.length/40;
			//inc += a.length/80;
			//inc += a.length/200;
			inc += 0.002+a.length/20;
		}
		private function moveLinear(a:Point):void {
			var speed:Number = 0;
			/*
			if (food) {
				var target:Point = getTarget(food);
				var angle:Number = Math.atan2(target.y-p.y, target.x-p.x);
				
				speed = Math.max(-0.3, Math.min(0.3, Math.sqrt(Math.pow(target.y-p.y, 2)+Math.pow(target.x-p.x, 2))/400));
				//if (Math.abs(speed) > 0.015) {
				ang += angleDifference(angle+(Math.random()-0.5)*2, ang)/(10+speed);
				ang %= Math.PI*2;
				//}
			}
			*/
			
			var dist:Number = 0;
			if (target) {
				var angle:Number = Math.atan2(target.y-p.y, target.x-p.x);
				
				//speed = Math.max(-0.3, Math.min(0.3, Math.sqrt(Math.pow(target.y-p.y, 2)+Math.pow(target.x-p.x, 2))/400));
				dist = Point.distance(target, p);
				
				//speed = dist < 30 ? 0 : Math.max(-0.3, Math.min(0.3, dist/4000));
				speed = dist < 30 ? 0 : Math.max(-0.01, Math.min(0.01, dist/20000));
				
				
				//if (Math.abs(speed) > 0.015) {
				//if (Math.abs(speed) > 0.0015) {
					ang += angleDifference(angle+(Math.random()-0.5)*2, ang)/(10+speed);
					ang %= Math.PI*2;
				//}
			}
			
			a.x = Math.cos(ang)*speed;
			a.y = Math.sin(ang)*speed;
			
			for (var i:int = 0; i < TENTACLES; i++) {
				var t:Tentacle = tentacles[i];
				var ta:Number = (inc+i/TENTACLES)*Math.PI*2;
				
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)/2, (Math.sin(ta+Math.PI/2)+1)/2);
				//t.update(time, i/TENTACLES*Math.PI*2+time/10);
				
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)/2);
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)/1.2);
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)*1.3);
				//t.update(p, inc, Math.PI+ang+Math.sin(ta)*(0.1+dist/150));
				t.pos.x = p.x;
				t.pos.y = p.y;
				t.angle = Math.PI+ang+Math.sin(ta)*(0.1+dist/150);
			}
			
			//inc += a.length/5;
			inc += a.length*0.75;
		}
		/*
		private function removeSpread():void {
			var rem:Boolean = false;
			for (var i:int = 0; i < TENTACLES; i++) {
				var t:Tentacle = tentacles[i] as Tentacle;
				var ta:Number = (inc+i/TENTACLES)*Math.PI*2;
				if (t.shorten()) {
					rem = true;
				} else {
					t.update(p, inc, (Math.PI+ang+ta+inc*Math.PI)%(Math.PI*2));
				}
			}
			if (rem) {
				dispatchEvent(new Event(Event.CLOSE));
			}
			
			inc += 0.02;
		}
		*/
		
		/**
		 * @link http://www.cs.rit.edu/~ncs/color/t_convert.html
		 */
		private function getHue(rgb:uint):Number {
			var r:Number = ((rgb >>> 16) & 0xFF)/0xFF;
			var g:Number = ((rgb >>> 8) & 0xFF)/0xFF;
			var b:Number = (rgb & 0xFF)/0xFF;
			var min:Number = Math.min(r, g, b);
			var max:Number = Math.max(r, g, b);
			//*v = max;				// v

			var delta:Number = max - min;
			/*
			if (max != 0) {
				s = delta / max;		// s
			} else {
				// r = g = b = 0		// s = 0, v is undefined
				*s = 0;
				*h = -1;
				return;
			}
			*/
			
			if (max == 0) {
				return 0;
			}

			var h:Number;
			if (r == max)		h = (g-b)/delta;	// between yellow & magenta
			else if (g == max)	h = 2+(b-r)/delta;	// between cyan & yellow
			else				h = 4+(r-g)/delta;	// between magenta & cyan
			
			h /= 6;
			if (h < 0) h += 1;
			
			return h;
		}
		private function angleDifference(a1:Number, a2:Number):Number {
			var angle:Number = a1-a2;
			if (Math.abs(angle) > Math.PI) {
				angle = angle > 0 ? angle-Math.PI*2 : Math.PI*2+angle;
			}
			return angle;
		}
	}
}